package uf;

/**
 * 标准的并查集，包含路径压缩和按大小合并，两个关键步骤
 */
public class UF {
    private int[] parent;
    private int[] size;
    private int count; // 连通分量数量
    private int maxSize; // 当前最大连通分量大小

    public UF(int n) {
        parent = new int[n];
        size = new int[n];
        count = n;
        maxSize = 1;

        for (int i = 0; i < n; i++) {
            parent[i] = i;
            size[i] = 1;
        }
    }

    /**
     * 查找根节点，带路径压缩优化
     */
    public int find(int x) {
        // 路径压缩优化
        if (parent[x] != x) {
            parent[x] = find(parent[x]);
        }
        return parent[x];
    }

    /**
     * 合并两个集合
     */
    public void join(int p, int q) {
        int rootP = find(p);
        int rootQ = find(q);

        if (rootP == rootQ) {
            return;
        }

        // 按大小合并优化：小树合并到大树下
        if (size[rootP] > size[rootQ]) {
            parent[rootQ] = rootP;
            size[rootP] += size[rootQ];
            maxSize = Math.max(maxSize, size[rootP]);
        } else {
            parent[rootP] = rootQ;
            size[rootQ] += size[rootP];
            maxSize = Math.max(maxSize, size[rootQ]);
        }

        count--;
    }

    /**
     * 判断两个元素是否连通
     */
    public boolean connected(int p, int q) {
        return find(p) == find(q);
    }

    /**
     * 获取连通分量数量
     */
    public int count() {
        return count;
    }

    /**
     * 获取最大连通分量大小
     */
    public int getMaxConnectSize() {
        return maxSize;
    }
}

class UFTests {
    public static void main(String[] args) {
        // 测试1: 基本功能测试
        testBasicOperations();

        // 测试2: 大规模数据测试
        testLargeDataSet();

        // 测试3: 最大连通分量测试
        testMaxConnectedComponent();
    }

    private static void testBasicOperations() {
        UF uf = new UF(5);
        System.out.println("初始连通分量数量: " + uf.count()); // 应为5

        uf.join(0, 1);
        System.out.println("合并后连通分量数量: " + uf.count()); // 应为4
        System.out.println("0和1是否连通: " + uf.connected(0, 1)); // true
        System.out.println("0和2是否连通: " + uf.connected(0, 2)); // false

        uf.join(1, 2);
        System.out.println("再次合并后连通分量数量: " + uf.count()); // 应为3
        System.out.println("0和2是否连通: " + uf.connected(0, 2)); // true
        System.out.println("-----------------------------------------\n");
    }

    private static void testLargeDataSet() {
        int size = 10000;
        UF uf = new UF(size);

        // 合并所有偶数节点
        for (int i = 2; i < size; i += 2) {
            uf.join(i - 2, i);
        }

        // 合并所有奇数节点
        for (int i = 3; i < size; i += 2) {
            uf.join(i - 2, i);
        }

        System.out.println("大规模数据测试 - 连通分量数量: " + uf.count()); // 应为2
        System.out.println("0和" + (size - 2) + "是否连通: " + uf.connected(0, size - 2)); // true
        System.out.println("1和" + (size - 1) + "是否连通: " + uf.connected(1, size - 1)); // true
        System.out.println("0和1是否连通: " + uf.connected(0, 1)); // false
        System.out.println("-----------------------------------------\n");
    }

    private static void testMaxConnectedComponent() {
        UF uf = new UF(10);

        // 创建大小为4的连通分量
        uf.join(0, 1);
        uf.join(1, 2);
        uf.join(2, 3);

        // 创建大小为3的连通分量
        uf.join(4, 5);
        uf.join(5, 6);

        System.out.println("最大连通分量测试:");
        System.out.println("当前最大连通分量大小: " + uf.getMaxConnectSize()); // 应为4

        // 合并两个连通分量
        uf.join(3, 4);
        System.out.println("合并后最大连通分量大小: " + uf.getMaxConnectSize()); // 应为7
    }
}